package org.bingo.service;

import cn.dev33.satoken.stp.StpUtil;
import org.bingo.entity.User;
import org.bingo.entity.Video;
import org.bingo.entity.VideoIndex;
import org.bingo.entity.VideoType;
import org.bingo.repository.UserRepository;
import org.bingo.repository.VideoIndexRepository;
import org.bingo.repository.VideoRepository;
import org.bingo.repository.VideoTypeRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;

@Service
public class VideoService {

    @Autowired
    private VideoRepository videoRepository;

    @Autowired
    private VideoTypeRepository videoTypeRepository;

    @Autowired
    private VideoIndexRepository videoIndexRepository;

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private FileService fileService;

    @Transactional
    public List<Video> getVideoByPage(Integer page, Integer countPerPage) {
        Page<Video> pageOfVideo = videoRepository.findAll(PageRequest.of(page, countPerPage));
        return pageOfVideo.getContent();
    }

    @Transactional
    public List<Video> getVideoByType(String type) {
        VideoType videoType = videoTypeRepository.findByTypeName(type);
        if (videoType == null) {
            return new ArrayList<>();
        }

        List<Video> videoList = videoType.getVideoList();
        return videoList;
    }

    @Transactional
    public List<Video> getVideoLikeTitle(String title) {
        List<Video> videoList = videoRepository.findByTitleLike("%" + title + "%");
        return videoList;
    }

    public Video getVideoInfo(Long id) {
        return videoRepository.findById(id).orElse(null);
    }

    @Transactional
    public Long addVideo(String title,
                         String coverImageUrl,
                         String description,
                         String m3u8Url,
                         String type) {
        VideoIndex videoIndex = videoIndexRepository.findByM3u8Url(m3u8Url);
        if (videoIndex == null) {
            return -1L;
        }

        Long id = StpUtil.getLoginIdAsLong();
        User user = userRepository.findById(id).orElse(null);
        if (user == null) {
            return -2L;
        }

        VideoType videoType = videoTypeRepository.findByTypeName(type);
        if (videoType == null) {
            return -3L;
        }

        Video video = new Video();
        video.setTitle(title);
        video.setM3u8Url(m3u8Url);
        video.setDescription(description);
        video.setCoverImageUrl(coverImageUrl);
        video.setLikeCount(0L);
        video.setVideoType(videoType);
        video.setVideoIndex(videoIndex);
        video.setVideoOriginName(videoIndex.getVideoOriginName());
        video.setUser(user);
        videoRepository.save(video);
        videoIndex.setVideo(video);
        videoIndexRepository.save(videoIndex);

        return video.getId();
    }

    @Transactional
    public Long delVideo(Long videoId) {
        Video video = videoRepository.findById(videoId).orElse(null);
        if (video == null) {
            return -1L;
        }

        if (StpUtil.getLoginIdAsLong() != video.getUser().getId()) {
            return -2L;
        }

        List<String> fileServerNames = new ArrayList<>();
        fileServerNames.add(video.getVideoIndex().getVideoOriginName());
        video.getVideoIndex().getVideoEntityList().forEach(videoEntity -> {
            fileServerNames.add(videoEntity.getVideoTsOriginName());
        });
        videoRepository.delete(video);
        fileService.releaseVideo(fileServerNames);
        return videoId;
    }

    public boolean liked(Long videoId) {
        return userLikeVideo(StpUtil.getLoginIdAsLong(), videoId);
    }

    @Transactional
    public boolean userLikeVideo(Long userId, Long videoId) {
        User user = userRepository.findById(userId).orElse(null);
        if (user == null) {
            return false;
        }

        for (Video video : user.getLikeVideos()) {
            if (video.getId().equals(videoId)) {
                return true;
            }
        }
        return false;
    }

    @Transactional
    public Long likeVideo(Long id) {
        Video video = videoRepository.findById(id).orElse(null);
        if (video == null) {
            return -1L;
        }

        User user = userRepository.findById(StpUtil.getLoginIdAsLong()).orElse(null);
        if (userLikeVideo(user.getId(), video.getId())) {
            return video.getLikeCount();
        }
        video.setLikeCount(video.getLikeCount() + 1);
        videoRepository.save(video);
        user.getLikeVideos().add(video);
        userRepository.save(user);

        return video.getLikeCount();
    }

    @Transactional
    public Long dislikeVideo(Long id) {
        Video video = videoRepository.findById(id).orElse(null);
        if (video == null) {
            return -1L;
        }

        User user = userRepository.findById(StpUtil.getLoginIdAsLong()).orElse(null);
        if (!userLikeVideo(user.getId(), video.getId())) {
            return video.getLikeCount();
        }
        video.setLikeCount(video.getLikeCount() - 1);
        videoRepository.save(video);
        user.getLikeVideos().remove(video);
        userRepository.save(user);

        return video.getLikeCount();
    }

    public boolean collected(Long videoId) {
        return userCollectVideo(StpUtil.getLoginIdAsLong(), videoId);
    }

    @Transactional
    public boolean userCollectVideo(Long userId, Long videoId) {
        User user = userRepository.findById(userId).orElse(null);
        if (user == null) {
            return false;
        }

        for (Video video : user.getCollectVideos()) {
            if (video.getId().equals(videoId)) {
                return true;
            }
        }
        return false;
    }

    @Transactional
    public Integer collectVideo(Long id) {
        Video video = videoRepository.findById(id).orElse(null);
        if (video == null) {
            return -1;
        }

        User user = userRepository.findById(StpUtil.getLoginIdAsLong()).orElse(null);
        if (userCollectVideo(user.getId(), video.getId())) {
            return 0;
        }
        user.getCollectVideos().add(video);
        userRepository.save(user);
        return 0;
    }

    @Transactional
    public Integer uncollectVideo(Long id) {
        Video video = videoRepository.findById(id).orElse(null);
        if (video == null) {
            return -1;
        }

        User user = userRepository.findById(StpUtil.getLoginIdAsLong()).orElse(null);
        if (!userCollectVideo(user.getId(), video.getId())) {
            return 0;
        }
        user.getCollectVideos().remove(video);
        userRepository.save(user);
        return 0;
    }

    @Transactional
    public Integer updateVideo(Long id, String title, String description) {
        Video video = videoRepository.findById(id).orElse(null);
        if (video == null) {
            return -1;
        }

        if (!video.getUser().getId().equals(StpUtil.getLoginIdAsLong())) {
            return -2;
        }

        video.setTitle(title);
        video.setDescription(description);
        videoRepository.save(video);
        return 0;
    }

    public List<VideoType> getAllVideoType() {
        return videoTypeRepository.findAll();
    }
}
